/*==============================================================================
                              Includes
==============================================================================*/
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/systick.h"
#include "utils/ustdlib.h"
#include "driverlib/uart.h"
#include "inc/lm3s8962.h"
#include "utils/uartstdio.h"

/*==============================================================================
                              Defines
==============================================================================*/
#define SYSTICK_IN_SEC          ( 2 )

#define BUTTON_UP               ( 0x00000001 )

#define BUTTON_DOWN             ( 0x00000002 )

#define BUTTON_LEFT             ( 0x00000004 )

#define BUTTON_RIGHT            ( 0x00000008 )

/*==============================================================================
                        Local/Private Function Protoypes
==============================================================================*/
static void GPIO_fnInitButtons( void );
static void UART_fnInitDBG( void );
static void SYSTICK_fnInitTimer( unsigned short uiPeriodSec );

/*==============================================================================
                           Function Definitions
==============================================================================*/

/*============================================================================*/
/*!

//fn  ISR_systickHandler

\brief
    The interrupt service routine that is used as a timer

\param[in]
    Nothing

\return
    Nothing

\details
    This ISR prints a message to a destinated debug console whenevner the 
    systick sends an interrupt signal to the processor depending on the time 
    configured.

\code
REVISION HISTORY:

Version: 1.00    Date: 05-July-2012    By: Peter Hsiao
    - Created

\endcode

*/
/*============================================================================*/
void ISR_systickHandler( void )
{
    UARTprintf( "%d second is passed...\r\n", SYSTICK_IN_SEC );
}

/*============================================================================*/
/*!

//fn  ISR_cbGpioEbuttHandler

\brief
    The interrupt service routine that handles button presses

\param[in]
    Nothing

\return
    Nothing

\details
    This ISR is triggered whenever an arrow button is pressed on the host device
    . A message is print to a destinated debug console according to which button 
    is pressed.

\code
REVISION HISTORY:

Version: 1.00    Date: 05-July-2012    By: Peter Hsiao
    - Created

\endcode

*/
/*============================================================================*/
void ISR_cbGpioEbuttHandler( void )
{
   unsigned long ulButt;
   
   // Reads the status of the button GPIO pins
   ulButt = (unsigned long) GPIOPinIntStatus( GPIO_PORTE_BASE, true);
   
   // Prints a message to the debug console according to the button pressed
   switch( ulButt )
   {
      case BUTTON_UP:
          UARTprintf( "Up\r\n" );
          break;
          
      case BUTTON_DOWN:
          UARTprintf( "Down\r\n" );
          break;
          
      case BUTTON_LEFT:
          UARTprintf( "Left\r\n" );  
          break;
            
      case BUTTON_RIGHT:
          UARTprintf( "Right\r\n" );  
          break;  
      
      default:
          UARTprintf( "Err...\r\n" );  
          break;                    
   }
}

/*============================================================================*/
/*!

//fn  main

\brief
    The main fucntion

\param[in]
    Nothing

\return
    Nothing

\details

\code
REVISION HISTORY:

Version: 1.00    Date: 05-July-2012    By: Peter Hsiao
    - Created

\endcode

*/
/*============================================================================*/
int main()
{
    volatile unsigned long ulLoop;

    // Set the clocking to run directly from the crystal.
    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
                   SYSCTL_XTAL_8MHZ);
    
    // Initialize and configure the GPIO pins for push buttons' interrupt
    GPIO_fnInitButtons();
    
    // Initialize and configure the UART pins for debugging on "hyperterminals"
    UART_fnInitDBG();
    
    // Initialize a systick timer that triggers every SYSTICK_IN_SEC seconds
    SYSTICK_fnInitTimer( SYSTICK_IN_SEC );
   
    while(1)
    {        

    }
    
    return 0;
}

/*============================================================================*/
/*!

//fn  GPIO_fnInitButtons

\brief
    Initialize GPIO pins for arrow buttons on the host device

\param[in]
    Nothing

\return
    Nothing

\details

\code
REVISION HISTORY:

Version: 1.00    Date: 05-July-2012    By: Peter Hsiao
    - Created

\endcode

*/
/*============================================================================*/
static void GPIO_fnInitButtons( void )
{
    // Enable the GPIO pin to read the arrow buttons.
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    
    // Register interrupt service routine for GPIO on Port E
    GPIOPortIntRegister( GPIO_PORTE_BASE, ISR_cbGpioEbuttHandler );
    
    // Set Pin0 - Pin 3 on GPIO port E as input pins
    GPIOPinTypeGPIOInput( GPIO_PORTE_BASE,
                          GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 );

    // Config GPIO pad as examples indicated
    GPIOPadConfigSet( GPIO_PORTE_BASE,
                      GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3,
                      GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU );
    
    // Configure how the interrupts should be triggered (LOW_LEVEL in this case)
    GPIOIntTypeSet( GPIO_PORTE_BASE,
                    GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3,
                    GPIO_LOW_LEVEL );
    
    // Enable the GPIO Interrupt
    GPIOPinIntEnable( GPIO_PORTE_BASE, 
                      GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 );  
}

/*============================================================================*/
/*!

//fn  UART_fnInitDBG

\brief
    Initialize UART pins in order to output debug message on destinated debug
    console

\param[in]
    Nothing

\return
    Nothing

\details

\code
REVISION HISTORY:

Version: 1.00    Date: 05-July-2012    By: Peter Hsiao
    - Created

\endcode

*/
/*============================================================================*/
static void UART_fnInitDBG( void )
{
    // Enable the peripherals used by UART
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);    
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);    
    
    // Set GPIO A0 and A1 as UART pins.
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    
    // Configure the UART for 115,200, 8-N-1 operation.
    UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), 115200,
                        (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
                         UART_CONFIG_PAR_NONE));
    
    // Enable the UART feature    
    UARTEnable( UART0_BASE );
    
    // Initialize the UART so it can be used as a basic device for stdio
    UARTStdioInit( 0 );  
}

/*============================================================================*/
/*!

//fn  SYSTICK_fnInitTimer

\brief
    Initialize the systick to send interrupt to processor every "uiPeriodSec"
    seconds so it can be used as a timer

\param[in]
    uiPeriodSec
        Number of seconds an interrupt is to be sent to CPU

\return
    Nothing

\details

\code
REVISION HISTORY:

Version: 1.00    Date: 05-July-2012    By: Peter Hsiao
    - Created

\endcode

*/
/*============================================================================*/
static void SYSTICK_fnInitTimer( unsigned short uiPeriodSec )
{
    // Register the systick interrupt
    SysTickIntRegister( ISR_systickHandler );
    
    // Configure SysTick for a "uiPeriod" seconds interrupt.
    SysTickPeriodSet(SysCtlClockGet() * uiPeriodSec);
    
    // Enable systick and systick interrupt
    SysTickEnable();
    SysTickIntEnable();    
}